﻿using System;
using System.Drawing;
using AForge.Imaging;
using System.Drawing.Imaging;
using System.Collections.Generic;
using BrainTechLLC.ImageOperators;
using System.Diagnostics;
using AForge.Imaging.Filters;
using System.Threading;
using BrainTechLLC.ImageOperatorsNonAForgeDependent;
using BrainTechLLC;

namespace BrainTechLLC.FilterExtensions
{
    [Serializable]
    public abstract partial class SingleFilterBase : BaseNotifyPropertyChanged, IObjectLock, ISingleFilter
    {
        public virtual Bitmap Apply(string fileName, Bitmap bmp, bool returnCopyIfNoAction, bool wantPostProcessInfo, ref List<RGBAndCoordinate> postProcessInfo, ref int width, ref int height)
        {
            postProcessInfo = null;
            Bitmap dstImage = null;
            width = 0;
            height = 0;

            if (bmp == null)
                return null;

            if (Disabled)
            {
                if (returnCopyIfNoAction)
                {
                    return bmp.Clone() as Bitmap;
                }
                else
                {
                    return bmp;
                }
            }

            OnBeforeFilterBitmap(bmp, Name, fileName, null);

            // lock source bitmap data
            BitmapData imageData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);

            try
            {
                dstImage = Apply(fileName, imageData, wantPostProcessInfo, ref postProcessInfo, ref width, ref height);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Debug.WriteLine(ex.ToString());
                Debug.Assert(false);
            }
            finally
            {
                bmp.UnlockBits(imageData);
            }

            OnAfterFilterBitmap(dstImage, Name, fileName, null);
            return dstImage;
        }

        public virtual Bitmap Apply(string fileName, BitmapData imageData, bool wantPostProcessInfo, ref List<RGBAndCoordinate> postProcessInfo, ref int width, ref int height)
        {
            postProcessInfo = null;
            UnmanagedImage dstUnmanagedImage = Apply(fileName, new UnmanagedImage(imageData), wantPostProcessInfo, ref postProcessInfo, ref width, ref height);
            Bitmap dstImage = dstUnmanagedImage.ToManagedImage();
            dstUnmanagedImage.Dispose();
            return dstImage;
        }

        public virtual Bitmap Apply(string fileName, Bitmap bm, bool returnCopyIfNoAction)
        {
            List<RGBAndCoordinate> postProcessInfo = null;
            int width = 0;
            int height = 0;

            OnBeforeFilterBitmap(bm, Name, fileName, null);
            var bmOut = Apply(fileName, bm, returnCopyIfNoAction, false, ref postProcessInfo, ref width, ref height);
            OnAfterFilterBitmap(bmOut, Name, fileName, null);

            return bmOut;
        }

        public abstract UnmanagedImage Apply(string fileName, UnmanagedImage image, bool wantPostProcessInfo, ref List<RGBAndCoordinate> postProcessInfo, ref int width, ref int height);

        public abstract string Name { get; }

        public bool ProcessBitmap(FrameInfo frameInfo)
        {
            Bitmap bm = frameInfo.Bitmap;
            OnBeforeFilterBitmap(bm, "ProcessBitmap", string.Empty, null);
            bm = Apply(string.Empty, bm, false);
            OnAfterFilterBitmap(bm, "ProcessBitmap", string.Empty, null);
            frameInfo.Bitmap = bm;

            return true;
        }

        public void OnBeforeFilterBitmap(Bitmap bm, string description, string fileName, ISingleFilter filter)
        {
            if (_beforeFilterBitmap == null)
            {
                Interlocked.CompareExchange<FastSmartWeakEvent<EventHandler<ObjectEventArgs<Bitmap, string, string, ISingleFilter>>>>(ref _beforeFilterBitmap, new FastSmartWeakEvent<EventHandler<ObjectEventArgs<Bitmap, string, string, ISingleFilter>>>(), null);
            }
            _beforeFilterBitmap.Raise(this, new ObjectEventArgs<Bitmap, string, string, ISingleFilter>(bm, description, fileName, filter));
        }

        public void OnAfterFilterBitmap(Bitmap bm, string description, string fileName, ISingleFilter filter)
        {
            if (_afterFilterBitmap == null)
            {
                Interlocked.CompareExchange<FastSmartWeakEvent<EventHandler<ObjectEventArgs<Bitmap, string, string, ISingleFilter>>>>(ref _afterFilterBitmap, new FastSmartWeakEvent<EventHandler<ObjectEventArgs<Bitmap, string, string, ISingleFilter>>>(), null);
            }
            _afterFilterBitmap.Raise(this, new ObjectEventArgs<Bitmap, string, string, ISingleFilter>(bm, description, fileName, filter));
        }
    }
}
